#include "networkprotocol.h"

NetworkProtocol::NetworkProtocol()
{
    qDebug() << "Creating NetworkProtocol";
}

void NetworkProtocol::doRun()
{
    this->client = new QTcpSocket();

    QObject::connect(this->client, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
    QObject::connect(this->client, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
    QObject::connect(this->client, SIGNAL(readyRead()), this, SLOT(readData()));
//    this->start();

    qDebug() << "Running NetworkProtocol";
//    connect(this->client, SIGNAL(connected()), this, SLOT(onConnect()));


    this->client->connectToHost(QHostAddress(STALK_HOST), STALK_PORT);
    this->client->waitForConnected(5000);
    if(this->client->state() == QAbstractSocket::ConnectedState)
    {
        qDebug() << "Connection successful";
        emit onConnect();
    }
    else
    {
        qDebug() << "Socket error: " << this->client->error();
        emit onConnectionFailed();
        return;
    }

//    QEventLoop loop;
//    loop.exec();

//    while(1)
//    {
//        this->processOutQueue();
//        this->processInQueue();
//        this->usleep(100000);
//        QCoreApplication::processEvents();
//    }
}

void NetworkProtocol::processInQueue()
{
//    qDebug() << "processInQueue()";

    unsigned int packetLength;
    unsigned int packetType;
    unsigned int leftToRead;
    qint64 bytesAvailable;
    QByteArray rawData;

//    QByteArray data =
    //nBytesRead = this->client->read(head, 6);
    //this->client->waitForReadyRead(10000);

    // this->client->waitForReadyRead(1);
    qDebug() << "Available bytes to read: " << this->client->bytesAvailable();

    this->client->waitForReadyRead(100);
    bytesAvailable = this->client->bytesAvailable();

    rawData = this->client->read(6);

    if(rawData.length() == 6)
    {
        //data = new char[packetLength];
        qDebug() << "Received header: " << this->repr(rawData);
        qDebug() << "Received data length: " << rawData.length();
//        qDebug() << bytesAvailable;
        packetLength  =  rawData.at(0)& 0xFF;
        qDebug() << packetLength;
        packetLength |= (rawData.at(1) << 8)  & 0xFF00;
        qDebug() << packetLength;
        packetLength |= (rawData.at(2) << 16) & 0xFF0000;
        qDebug() << packetLength;
        packetLength |= (rawData.at(3) << 32) & 0xFF000000;
        qDebug() << packetLength;

        packetType  =  rawData.at(4)       & 0x00FF;
        packetType |= (rawData.at(5) << 8) & 0xFF00;

        qDebug() << "Packet length: " << packetLength;
        qDebug() << "Packet type: " << packetType;

        rawData.clear();

        qDebug() << "Reading packet data...";

        while(rawData.length() < packetLength)
        {
            qDebug() << "Waiting for data. Current socket state: " << this->client->state();
//            this->client->waitForReadyRead(10000);
            qDebug() << "Can read bytes: " << this->client->bytesAvailable();
            qDebug() << this->client->readBufferSize();
            //while(!this->client->bytesAvailable());
            leftToRead = packetLength - rawData.length();
            rawData.append(this->client->read(leftToRead > 512 ? 512 : leftToRead));
            qDebug() << "Received so far: " << rawData.length();
//            this->usleep(20000);
        }

//        qDebug() << this->client->read(18);

        // rawData = this->client->readAll();

        qDebug() << "Received packet data length: " << rawData.length();

        NetworkPacket *packet = new NetworkPacket(packetType, rawData);
        emit onGotPacket(packet);
    }
}

void NetworkProtocol::processOutQueue()
{
//    qDebug() << "processOutQueue()";
    while(!this->outQueue.isEmpty())
    {
        NetworkPacket *packet = this->outQueue.dequeue();
        QByteArray rawData;
        rawData = packet->rawData();
//        qDebug() << "Sending packet. Raw data: " << this->repr(rawData);
        qDebug() << "Sending packet. Raw data length: " << rawData.length();
        this->client->write(rawData);
        if(!this->client->waitForBytesWritten(5000))
        {
            qDebug() << "Socket error: " << this->client->errorString();
            emit onError();
        }
        qDebug() << "Packet sent.";
    }
}

QString NetworkProtocol::repr(QByteArray rawData)
{
    QString repr;
    for(int i = 0; i < rawData.length(); i++)
    {
        if(i)
        {
            repr += " ";
        }
        repr += QString::number((unsigned char)rawData.at(i), 16).rightJustified(2, '0');
    }
    return repr;
}

void NetworkProtocol::waitForReady()
{
    while(this->client->state() != QTcpSocket::ConnectedState &&
          this->client->state() != QTcpSocket::UnconnectedState)
    {
    }
}

void NetworkProtocol::sendPacket(NetworkPacket *packet)
{
    //this->outQueue.enqueue(packet);
    this->client->write(packet->rawData());
}

/*void NetworkProtocol::onConnect()
{
    qDebug() << "Connection successful";
}*/

void NetworkProtocol::onSocketError(QAbstractSocket::SocketError error)
{
    qDebug() << "Socket error: " << error;
//    emit onError();
}

void NetworkProtocol::onSocketStateChanged(QAbstractSocket::SocketState state)
{
    qDebug() << "Socket state: " << int(state);
}

void NetworkProtocol::readData()
{
    while(this->client->bytesAvailable())
    {
        qDebug() << "GOT DATA!";

        unsigned int packetLength;
        unsigned int packetType;
        unsigned int leftToRead;
        qint64 bytesAvailable;
        QByteArray rawData;

        qDebug() << "Available bytes to read: " << this->client->bytesAvailable();

        this->client->waitForReadyRead(100);
        bytesAvailable = this->client->bytesAvailable();

        rawData = this->client->read(6);

        if(rawData.length() == 6)
        {
            qDebug() << "Received header: " << this->repr(rawData);
            qDebug() << "Received data length: " << rawData.length();
            packetLength  =  rawData.at(0)& 0xFF;
            packetLength |= (rawData.at(1) << 8)  & 0xFF00;
            packetLength |= (rawData.at(2) << 16) & 0xFF0000;
            packetLength |= (rawData.at(3) << 32) & 0xFF000000;

            packetType  =  rawData.at(4)       & 0x00FF;
            packetType |= (rawData.at(5) << 8) & 0xFF00;

            qDebug() << "Packet length: " << packetLength;
            qDebug() << "Packet type: " << packetType;

            rawData.clear();

            qDebug() << "Reading packet data...";

            while(rawData.length() < packetLength)
            {
                leftToRead = packetLength - rawData.length();
                rawData.append(this->client->read(leftToRead > 512 ? 512 : leftToRead));
                qApp->processEvents();
            }

            qDebug() << "Received packet data length: " << rawData.length();

            NetworkPacket *packet = new NetworkPacket(packetType, rawData);
            emit onGotPacket(packet);
        }
    }
}
